Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
CRAP
96.43% covered (success)
96.43%
1160 / 1203
PptCharts
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
212
96.43% covered (success)
96.43%
1160 / 1203
 render
0.00% covered (danger)
0.00%
0 / 1
5.02
90.91% covered (success)
90.91%
10 / 11
 writeChart
0.00% covered (danger)
0.00%
0 / 1
8.23
84.72% covered (warning)
84.72%
61 / 72
 writeSpreadsheet
0.00% covered (danger)
0.00%
0 / 1
7.04
90.32% covered (success)
90.32%
28 / 31
 writeElementWithValAttribute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 writeSingleValueOrReference
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
16 / 16
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
26 / 26
 writeTitle
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
48 / 48
 writePlotArea
100.00% covered (success)
100.00%
1 / 1
12
100.00% covered (success)
100.00%
28 / 28
 writeLegend
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
48 / 48
 writeLayout
0.00% covered (danger)
0.00%
0 / 1
5.27
77.78% covered (warning)
77.78%
21 / 27
 writeTypeArea
0.00% covered (danger)
0.00%
0 / 1
9.02
93.48% covered (success)
93.48%
43 / 46
 writeTypeBar
0.00% covered (danger)
0.00%
0 / 1
17.10
93.07% covered (success)
93.07%
94 / 101
 writeTypeBar3D
0.00% covered (danger)
0.00%
0 / 1
15
96.74% covered (success)
96.74%
89 / 92
 writeTypeDoughnut
0.00% covered (danger)
0.00%
0 / 1
20
95.29% covered (success)
95.29%
81 / 85
 writeTypePie
0.00% covered (danger)
0.00%
0 / 1
15.03
94.94% covered (success)
94.94%
75 / 79
 writeTypePie3D
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
76 / 76
 writeTypeLine
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
81 / 81
 writeTypeRadar
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
82 / 82
 writeTypeScatter
100.00% covered (success)
100.00%
1 / 1
16
100.00% covered (success)
100.00%
85 / 85
 writeChartRelationships
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
8 / 8
 writeSeriesMarker
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
19 / 19
 writeAxis
0.00% covered (danger)
0.00%
0 / 1
19
99.25% covered (success)
99.25%
133 / 134
 writeAxisGridlines
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
1<?php
2
3namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
4
5use PhpOffice\Common\Adapter\Zip\ZipInterface;
6use PhpOffice\Common\Drawing as CommonDrawing;
7use PhpOffice\Common\XMLWriter;
8use PhpOffice\PhpPresentation\PhpPresentation;
9use PhpOffice\PhpPresentation\Shape\Chart;
10use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
11use PhpOffice\PhpPresentation\Shape\Chart\Legend;
12use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
13use PhpOffice\PhpPresentation\Shape\Chart\Title;
14use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
15use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
16use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
17use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
18use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
19use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
20use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
21use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
22use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
23use PhpOffice\PhpPresentation\Style\Border;
24use PhpOffice\PhpPresentation\Style\Fill;
25use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
26use PhpOffice\PhpSpreadsheet\IOFactory;
27use PhpOffice\PhpSpreadsheet\Spreadsheet;
28
29class PptCharts extends AbstractDecoratorWriter
30{
31    /**
32     * @throws \Exception
33     */
34    public function render(): ZipInterface
35    {
36        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
37            $shape = $this->getDrawingHashTable()->getByIndex($i);
38            if ($shape instanceof Chart) {
39                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
40
41                if ($shape->hasIncludedSpreadsheet()) {
42                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
43                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
44                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
45
46                    // remove temp file
47                    if (false === @unlink($pFilename)) {
48                        throw new \Exception('The file ' . $pFilename . ' could not removed.');
49                    }
50                }
51            }
52        }
53
54        return $this->getZip();
55    }
56
57    /**
58     * Write chart to XML format.
59     *
60     * @return string XML Output
61     *
62     * @throws \Exception
63     */
64    public function writeChart(Chart $chart): string
65    {
66        // Create XML writer
67        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
68
69        // XML header
70        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
71
72        // c:chartSpace
73        $objWriter->startElement('c:chartSpace');
74        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
75        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
76        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
77
78        // c:date1904
79        $objWriter->startElement('c:date1904');
80        $objWriter->writeAttribute('val', '1');
81        $objWriter->endElement();
82
83        // c:lang
84        $objWriter->startElement('c:lang');
85        $objWriter->writeAttribute('val', 'en-US');
86        $objWriter->endElement();
87
88        // c:chart
89        $objWriter->startElement('c:chart');
90
91        // Title?
92        if ($chart->getTitle()->isVisible()) {
93            // Write title
94            $this->writeTitle($objWriter, $chart->getTitle());
95        }
96
97        // c:autoTitleDeleted
98        $objWriter->startElement('c:autoTitleDeleted');
99        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
100        $objWriter->endElement();
101
102        // c:view3D
103        $objWriter->startElement('c:view3D');
104
105        // c:rotX
106        $objWriter->startElement('c:rotX');
107        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
108        $objWriter->endElement();
109
110        // c:hPercent
111        $hPercent = $chart->getView3D()->getHeightPercent();
112        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
113
114        // c:rotY
115        $objWriter->startElement('c:rotY');
116        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
117        $objWriter->endElement();
118
119        // c:depthPercent
120        $objWriter->startElement('c:depthPercent');
121        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
122        $objWriter->endElement();
123
124        // c:rAngAx
125        $objWriter->startElement('c:rAngAx');
126        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
127        $objWriter->endElement();
128
129        // c:perspective
130        $objWriter->startElement('c:perspective');
131        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
132        $objWriter->endElement();
133
134        $objWriter->endElement();
135
136        // Write plot area
137        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
138
139        // Legend?
140        if ($chart->getLegend()->isVisible()) {
141            // Write legend
142            $this->writeLegend($objWriter, $chart->getLegend());
143        }
144
145        // c:plotVisOnly
146        $objWriter->startElement('c:plotVisOnly');
147        $objWriter->writeAttribute('val', '1');
148        $objWriter->endElement();
149
150        // c:dispBlanksAs
151        $objWriter->startElement('c:dispBlanksAs');
152        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
153        $objWriter->endElement();
154
155        $objWriter->endElement();
156
157        // c:spPr
158        $objWriter->startElement('c:spPr');
159
160        // Fill
161        $this->writeFill($objWriter, $chart->getFill());
162
163        // Border
164        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
165            $this->writeBorder($objWriter, $chart->getBorder(), '');
166        }
167
168        // Shadow
169        if ($chart->getShadow()->isVisible()) {
170            // a:effectLst
171            $objWriter->startElement('a:effectLst');
172
173            // a:outerShdw
174            $objWriter->startElement('a:outerShdw');
175            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
176            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
177            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle($chart->getShadow()->getDirection()));
178            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
179            $objWriter->writeAttribute('rotWithShape', '0');
180
181            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
182
183            $objWriter->endElement();
184
185            $objWriter->endElement();
186        }
187
188        $objWriter->endElement();
189
190        // External data?
191        if ($chart->hasIncludedSpreadsheet()) {
192            // c:externalData
193            $objWriter->startElement('c:externalData');
194            $objWriter->writeAttribute('r:id', 'rId1');
195
196            // c:autoUpdate
197            $objWriter->startElement('c:autoUpdate');
198            $objWriter->writeAttribute('val', '0');
199            $objWriter->endElement();
200
201            $objWriter->endElement();
202        }
203
204        $objWriter->endElement();
205
206        // Return
207        return $objWriter->getData();
208    }
209
210    /**
211     * Write chart to XML format.
212     *
213     * @return string String output
214     *
215     * @throws \Exception
216     */
217    public function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
218    {
219        // Need output?
220        if (!$chart->hasIncludedSpreadsheet()) {
221            throw new \Exception('No spreadsheet output is required for the given chart.');
222        }
223
224        // Create new spreadsheet
225        $spreadsheet = new Spreadsheet();
226
227        // Set properties
228        $title = $chart->getTitle()->getText();
229        if (0 == strlen($title)) {
230            $title = 'Chart';
231        }
232        $spreadsheet->getProperties()
233            ->setCreator(
234                $presentation->getDocumentProperties()->getCreator())->setLastModifiedBy(
235                    $presentation->getDocumentProperties()->getLastModifiedBy()
236                )
237            ->setTitle($title);
238
239        // Add chart data
240        $sheet = $spreadsheet->setActiveSheetIndex(0);
241        $sheet->setTitle('Sheet1');
242
243        // Write series
244        $seriesIndex = 0;
245        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
246            // Title
247            $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, 1, $series->getTitle());
248
249            // X-axis
250            $axisXData = array_keys($series->getValues());
251            $numAxisXData = count($axisXData);
252            for ($i = 0; $i < $numAxisXData; ++$i) {
253                $sheet->setCellValueByColumnAndRow(0, $i + 2, $axisXData[$i]);
254            }
255
256            // Y-axis
257            $axisYData = array_values($series->getValues());
258            $numAxisYData = count($axisYData);
259            for ($i = 0; $i < $numAxisYData; ++$i) {
260                $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, $i + 2, $axisYData[$i]);
261            }
262
263            ++$seriesIndex;
264        }
265
266        // Save to string
267        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
268        $writer->save($tempName);
269
270        // Load file in memory
271        $returnValue = file_get_contents($tempName);
272        if (false === @unlink($tempName)) {
273            throw new \Exception('The file ' . $tempName . ' could not removed.');
274        }
275
276        return $returnValue;
277    }
278
279    /**
280     * Write element with value attribute.
281     *
282     * @param XMLWriter $objWriter XML Writer
283     */
284    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
285    {
286        $objWriter->startElement($elementName);
287        $objWriter->writeAttribute('val', $value);
288        $objWriter->endElement();
289    }
290
291    /**
292     * Write single value or reference.
293     *
294     * @param XMLWriter $objWriter XML Writer
295     */
296    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
297    {
298        if (!$isReference) {
299            // Value
300            $objWriter->writeElement('c:v', $value);
301
302            return;
303        }
304
305        // Reference and cache
306        // c:strRef
307        $objWriter->startElement('c:strRef');
308        // c:strRef/c:f
309        $objWriter->writeElement('c:f', $reference);
310        // c:strRef/c:strCache
311        $objWriter->startElement('c:strCache');
312        // c:strRef/c:strCache/c:ptCount
313        $objWriter->startElement('c:ptCount');
314        $objWriter->writeAttribute('val', '1');
315        $objWriter->endElement();
316
317        // c:strRef/c:strCache/c:pt
318        $objWriter->startElement('c:pt');
319        $objWriter->writeAttribute('idx', '0');
320        // c:strRef/c:strCache/c:pt/c:v
321        $objWriter->writeElement('c:v', $value);
322        // c:strRef/c:strCache/c:pt
323        $objWriter->endElement();
324        // c:strRef/c:strCache
325        $objWriter->endElement();
326        // c:strRef
327        $objWriter->endElement();
328    }
329
330    /**
331     * Write series value or reference.
332     *
333     * @param XMLWriter $objWriter XML Writer
334     * @param array<int, mixed> $values
335     */
336    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
337    {
338        // c:strLit / c:numLit
339        // c:strRef / c:numRef
340        $referenceType = ($isReference ? 'Ref' : 'Lit');
341        $dataType = is_numeric($values[0]) ? 'num' : 'str';
342        $objWriter->startElement('c:' . $dataType . $referenceType);
343
344        $numValues = count($values);
345        if (!$isReference) {
346            // Value
347
348            // c:ptCount
349            $objWriter->startElement('c:ptCount');
350            $objWriter->writeAttribute('val', count($values));
351            $objWriter->endElement();
352
353            // Add points
354            for ($i = 0; $i < $numValues; ++$i) {
355                // c:pt
356                $objWriter->startElement('c:pt');
357                $objWriter->writeAttribute('idx', $i);
358                $objWriter->writeElement('c:v', $values[$i]);
359                $objWriter->endElement();
360            }
361        } else {
362            // Reference
363            $objWriter->writeElement('c:f', $reference);
364            $objWriter->startElement('c:' . $dataType . 'Cache');
365
366            // c:ptCount
367            $objWriter->startElement('c:ptCount');
368            $objWriter->writeAttribute('val', count($values));
369            $objWriter->endElement();
370
371            // Add points
372            for ($i = 0; $i < $numValues; ++$i) {
373                // c:pt
374                $objWriter->startElement('c:pt');
375                $objWriter->writeAttribute('idx', $i);
376                $objWriter->writeElement('c:v', $values[$i]);
377                $objWriter->endElement();
378            }
379
380            $objWriter->endElement();
381        }
382
383        $objWriter->endElement();
384    }
385
386    /**
387     * Write Title.
388     *
389     * @param XMLWriter $objWriter XML Writer
390     *
391     * @throws \Exception
392     */
393    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
394    {
395        // c:title
396        $objWriter->startElement('c:title');
397
398        // c:tx
399        $objWriter->startElement('c:tx');
400
401        // c:rich
402        $objWriter->startElement('c:rich');
403
404        // a:bodyPr
405        $objWriter->writeElement('a:bodyPr', null);
406
407        // a:lstStyle
408        $objWriter->writeElement('a:lstStyle', null);
409
410        // a:p
411        $objWriter->startElement('a:p');
412
413        // a:pPr
414        $objWriter->startElement('a:pPr');
415        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
416        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
417        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
418        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
419        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
420        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
421
422        // a:defRPr
423        $objWriter->writeElement('a:defRPr', null);
424
425        $objWriter->endElement();
426
427        // a:r
428        $objWriter->startElement('a:r');
429
430        // a:rPr
431        $objWriter->startElement('a:rPr');
432        $objWriter->writeAttribute('lang', 'en-US');
433        $objWriter->writeAttribute('dirty', '0');
434        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
435        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
436        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
437        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
438        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
439        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
440        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
441
442        // Font - a:solidFill
443        $objWriter->startElement('a:solidFill');
444
445        $this->writeColor($objWriter, $subject->getFont()->getColor());
446
447        $objWriter->endElement();
448
449        // Font - a:latin
450        $objWriter->startElement('a:latin');
451        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
452        $objWriter->endElement();
453
454        $objWriter->endElement();
455
456        // a:t
457        $objWriter->writeElement('a:t', $subject->getText());
458
459        $objWriter->endElement();
460
461        // a:endParaRPr
462        $objWriter->startElement('a:endParaRPr');
463        $objWriter->writeAttribute('lang', 'en-US');
464        $objWriter->writeAttribute('dirty', '0');
465        $objWriter->endElement();
466
467        $objWriter->endElement();
468
469        $objWriter->endElement();
470
471        $objWriter->endElement();
472
473        // Write layout
474        $this->writeLayout($objWriter, $subject);
475
476        // c:overlay
477        $objWriter->startElement('c:overlay');
478        $objWriter->writeAttribute('val', '0');
479        $objWriter->endElement();
480
481        $objWriter->endElement();
482    }
483
484    /**
485     * Write Plot Area.
486     *
487     * @param XMLWriter $objWriter XML Writer
488     *
489     * @throws \Exception
490     */
491    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
492    {
493        // c:plotArea
494        $objWriter->startElement('c:plotArea');
495
496        // Write layout
497        $this->writeLayout($objWriter, $subject);
498
499        // Write chart
500        $chartType = $subject->getType();
501        if ($chartType instanceof Area) {
502            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
503        } elseif ($chartType instanceof Bar) {
504            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
505        } elseif ($chartType instanceof Bar3D) {
506            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
507        } elseif ($chartType instanceof Doughnut) {
508            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
509        } elseif ($chartType instanceof Pie) {
510            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
511        } elseif ($chartType instanceof Pie3D) {
512            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
513        } elseif ($chartType instanceof Line) {
514            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
515        } elseif ($chartType instanceof Radar) {
516            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
517        } elseif ($chartType instanceof Scatter) {
518            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
519        } else {
520            throw new \Exception('The chart type provided could not be rendered.');
521        }
522
523        // Write X axis?
524        if ($chartType->hasAxisX()) {
525            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
526        }
527
528        // Write Y axis?
529        if ($chartType->hasAxisY()) {
530            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
531        }
532
533        $objWriter->endElement();
534    }
535
536    /**
537     * Write Legend.
538     *
539     * @param XMLWriter $objWriter XML Writer
540     * @param Chart\Legend $subject
541     *
542     * @throws \Exception
543     */
544    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
545    {
546        // c:legend
547        $objWriter->startElement('c:legend');
548
549        // c:legendPos
550        $objWriter->startElement('c:legendPos');
551        $objWriter->writeAttribute('val', $subject->getPosition());
552        $objWriter->endElement();
553
554        // Write layout
555        $this->writeLayout($objWriter, $subject);
556
557        // c:overlay
558        $objWriter->startElement('c:overlay');
559        $objWriter->writeAttribute('val', '0');
560        $objWriter->endElement();
561
562        // c:spPr
563        $objWriter->startElement('c:spPr');
564
565        // Fill
566        $this->writeFill($objWriter, $subject->getFill());
567
568        // Border
569        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
570            $this->writeBorder($objWriter, $subject->getBorder(), '');
571        }
572
573        $objWriter->endElement();
574
575        // c:txPr
576        $objWriter->startElement('c:txPr');
577
578        // a:bodyPr
579        $objWriter->writeElement('a:bodyPr', null);
580
581        // a:lstStyle
582        $objWriter->writeElement('a:lstStyle', null);
583
584        // a:p
585        $objWriter->startElement('a:p');
586
587        // a:pPr
588        $objWriter->startElement('a:pPr');
589        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
590        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
591        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
592        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
593        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
594        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
595
596        // a:defRPr
597        $objWriter->startElement('a:defRPr');
598
599        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
600        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
601        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
602        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
603        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
604        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
605        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
606
607        // Font - a:solidFill
608        $objWriter->startElement('a:solidFill');
609
610        $this->writeColor($objWriter, $subject->getFont()->getColor());
611
612        $objWriter->endElement();
613
614        // Font - a:latin
615        $objWriter->startElement('a:latin');
616        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
617        $objWriter->endElement();
618
619        $objWriter->endElement();
620
621        $objWriter->endElement();
622
623        // a:endParaRPr
624        $objWriter->startElement('a:endParaRPr');
625        $objWriter->writeAttribute('lang', 'en-US');
626        $objWriter->writeAttribute('dirty', '0');
627        $objWriter->endElement();
628
629        $objWriter->endElement();
630
631        $objWriter->endElement();
632
633        $objWriter->endElement();
634    }
635
636    /**
637     * Write Layout.
638     *
639     * @param XMLWriter $objWriter XML Writer
640     * @param Legend|PlotArea|Title $subject
641     *
642     * @throws \Exception
643     */
644    protected function writeLayout(XMLWriter $objWriter, $subject): void
645    {
646        // c:layout
647        $objWriter->startElement('c:layout');
648
649        // c:manualLayout
650        $objWriter->startElement('c:manualLayout');
651        // c:xMode
652        $objWriter->startElement('c:xMode');
653        $objWriter->writeAttribute('val', 'edge');
654        $objWriter->endElement();
655
656        // c:yMode
657        $objWriter->startElement('c:yMode');
658        $objWriter->writeAttribute('val', 'edge');
659        $objWriter->endElement();
660
661        if (0 != $subject->getOffsetX()) {
662            // c:x
663            $objWriter->startElement('c:x');
664            $objWriter->writeAttribute('val', $subject->getOffsetX());
665            $objWriter->endElement();
666        }
667
668        if (0 != $subject->getOffsetY()) {
669            // c:y
670            $objWriter->startElement('c:y');
671            $objWriter->writeAttribute('val', $subject->getOffsetY());
672            $objWriter->endElement();
673        }
674
675        if (0 != $subject->getWidth()) {
676            // c:w
677            $objWriter->startElement('c:w');
678            $objWriter->writeAttribute('val', $subject->getWidth());
679            $objWriter->endElement();
680        }
681
682        if (0 != $subject->getHeight()) {
683            // c:h
684            $objWriter->startElement('c:h');
685            $objWriter->writeAttribute('val', $subject->getHeight());
686            $objWriter->endElement();
687        }
688
689        $objWriter->endElement();
690        $objWriter->endElement();
691    }
692
693    /**
694     * Write Type Area.
695     *
696     * @param XMLWriter $objWriter XML Writer
697     * @param Chart\Type\Area $subject
698     *
699     * @throws \Exception
700     */
701    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
702    {
703        // c:lineChart
704        $objWriter->startElement('c:areaChart');
705
706        // c:grouping
707        $objWriter->startElement('c:grouping');
708        $objWriter->writeAttribute('val', 'standard');
709        $objWriter->endElement();
710
711        // Write series
712        $seriesIndex = 0;
713        foreach ($subject->getSeries() as $series) {
714            // c:ser
715            $objWriter->startElement('c:ser');
716
717            // c:ser > c:idx
718            $objWriter->startElement('c:idx');
719            $objWriter->writeAttribute('val', $seriesIndex);
720            $objWriter->endElement();
721
722            // c:ser > c:order
723            $objWriter->startElement('c:order');
724            $objWriter->writeAttribute('val', $seriesIndex);
725            $objWriter->endElement();
726
727            // c:ser > c:tx
728            $objWriter->startElement('c:tx');
729            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
730            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
731            $objWriter->endElement();
732
733            // c:ser > c:dLbls
734            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
735            $objWriter->startElement('c:dLbls');
736
737            // c:ser > c:dLbls > c:showVal
738            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
739
740            // c:ser > c:dLbls > c:showCatName
741            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
742
743            // c:ser > c:dLbls > c:showSerName
744            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
745
746            // c:ser > c:dLbls > c:showPercent
747            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
748
749            // c:ser > ##c:dLbls
750            $objWriter->endElement();
751
752            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
753                // c:spPr
754                $objWriter->startElement('c:spPr');
755                // Write fill
756                $this->writeFill($objWriter, $series->getFill());
757                // ## c:spPr
758                $objWriter->endElement();
759            }
760
761            // Write X axis data
762            $axisXData = array_keys($series->getValues());
763
764            // c:cat
765            $objWriter->startElement('c:cat');
766            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
767            $objWriter->endElement();
768
769            // Write Y axis data
770            $axisYData = array_values($series->getValues());
771
772            // c:val
773            $objWriter->startElement('c:val');
774            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
775            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
776            $objWriter->endElement();
777
778            $objWriter->endElement();
779
780            ++$seriesIndex;
781        }
782
783        // c:axId
784        $objWriter->startElement('c:axId');
785        $objWriter->writeAttribute('val', '52743552');
786        $objWriter->endElement();
787
788        // c:axId
789        $objWriter->startElement('c:axId');
790        $objWriter->writeAttribute('val', '52749440');
791        $objWriter->endElement();
792
793        $objWriter->endElement();
794    }
795
796    /**
797     * Write Type Bar.
798     *
799     * @param XMLWriter $objWriter XML Writer
800     * @param Chart\Type\Bar $subject
801     *
802     * @throws \Exception
803     */
804    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
805    {
806        // c:barChart
807        $objWriter->startElement('c:barChart');
808
809        // c:barDir
810        $objWriter->startElement('c:barDir');
811        $objWriter->writeAttribute('val', $subject->getBarDirection());
812        $objWriter->endElement();
813
814        // c:grouping
815        $objWriter->startElement('c:grouping');
816        $objWriter->writeAttribute('val', $subject->getBarGrouping());
817        $objWriter->endElement();
818
819        // Write series
820        $seriesIndex = 0;
821        foreach ($subject->getSeries() as $series) {
822            // c:ser
823            $objWriter->startElement('c:ser');
824
825            // c:idx
826            $objWriter->startElement('c:idx');
827            $objWriter->writeAttribute('val', $seriesIndex);
828            $objWriter->endElement();
829
830            // c:order
831            $objWriter->startElement('c:order');
832            $objWriter->writeAttribute('val', $seriesIndex);
833            $objWriter->endElement();
834
835            // c:tx
836            $objWriter->startElement('c:tx');
837            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
838            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
839            $objWriter->endElement();
840
841            // Fills for points?
842            $dataPointFills = $series->getDataPointFills();
843            foreach ($dataPointFills as $key => $value) {
844                // c:dPt
845                $objWriter->startElement('c:dPt');
846
847                // c:idx
848                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
849
850                if (Fill::FILL_NONE != $value->getFillType()) {
851                    // c:spPr
852                    $objWriter->startElement('c:spPr');
853                    // Write fill
854                    $this->writeFill($objWriter, $value);
855                    // ## c:spPr
856                    $objWriter->endElement();
857                }
858
859                // ## c:dPt
860                $objWriter->endElement();
861            }
862
863            // c:dLbls
864            $objWriter->startElement('c:dLbls');
865
866            if ($series->hasDlblNumFormat()) {
867                //c:numFmt
868                $objWriter->startElement('c:numFmt');
869                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
870                $objWriter->writeAttribute('sourceLinked', '0');
871                $objWriter->endElement();
872            }
873
874            // c:txPr
875            $objWriter->startElement('c:txPr');
876
877            // a:bodyPr
878            $objWriter->writeElement('a:bodyPr');
879
880            // a:lstStyle
881            $objWriter->writeElement('a:lstStyle');
882
883            // a:p
884            $objWriter->startElement('a:p');
885
886            // a:pPr
887            $objWriter->startElement('a:pPr');
888
889            // a:defRPr
890            $objWriter->startElement('a:defRPr');
891
892            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
893            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
894            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
895            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
896            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
897            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
898            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
899
900            // a:solidFill
901            $objWriter->startElement('a:solidFill');
902            $this->writeColor($objWriter, $series->getFont()->getColor());
903            // >a:solidFill
904            $objWriter->endElement();
905            // a:latin
906            $objWriter->startElement('a:latin');
907            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
908            // >a:latin
909            $objWriter->endElement();
910
911            // >a:defRPr
912            $objWriter->endElement();
913            // >a:pPr
914            $objWriter->endElement();
915
916            // a:endParaRPr
917            $objWriter->startElement('a:endParaRPr');
918            $objWriter->writeAttribute('lang', 'en-US');
919            $objWriter->writeAttribute('dirty', '0');
920            $objWriter->endElement();
921
922            // >a:p
923            $objWriter->endElement();
924            // >a:lstStyle
925            $objWriter->endElement();
926
927            // c:dLblPos
928            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
929
930            // c:showVal
931            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
932
933            // c:showCatName
934            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
935
936            // c:showSerName
937            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
938
939            // c:showPercent
940            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
941
942            // c:separator
943            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
944
945            // c:showLeaderLines
946            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
947
948            $objWriter->endElement();
949
950            // c:spPr
951            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
952                // c:spPr
953                $objWriter->startElement('c:spPr');
954                // Write fill
955                $this->writeFill($objWriter, $series->getFill());
956                // ## c:spPr
957                $objWriter->endElement();
958            }
959
960            // Write X axis data
961            $axisXData = array_keys($series->getValues());
962
963            // c:cat
964            $objWriter->startElement('c:cat');
965            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
966            $objWriter->endElement();
967
968            // Write Y axis data
969            $axisYData = array_values($series->getValues());
970
971            // c:val
972            $objWriter->startElement('c:val');
973            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
974            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
975            $objWriter->endElement();
976
977            $objWriter->endElement();
978
979            ++$seriesIndex;
980        }
981
982        // c:gapWidth
983        $objWriter->startElement('c:gapWidth');
984        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
985        $objWriter->endElement();
986
987        // c:overlap
988        $objWriter->startElement('c:overlap');
989        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
990        $objWriter->endElement();
991
992        // c:axId
993        $objWriter->startElement('c:axId');
994        $objWriter->writeAttribute('val', '52743552');
995        $objWriter->endElement();
996
997        // c:axId
998        $objWriter->startElement('c:axId');
999        $objWriter->writeAttribute('val', '52749440');
1000        $objWriter->endElement();
1001
1002        // c:extLst
1003        $objWriter->startElement('c:extLst');
1004        $objWriter->endElement();
1005
1006        $objWriter->endElement();
1007    }
1008
1009    /**
1010     * Write Type Bar3D.
1011     *
1012     * @param XMLWriter $objWriter XML Writer
1013     * @param Chart\Type\Bar3D $subject
1014     *
1015     * @throws \Exception
1016     */
1017    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1018    {
1019        // c:bar3DChart
1020        $objWriter->startElement('c:bar3DChart');
1021
1022        // c:barDir
1023        $objWriter->startElement('c:barDir');
1024        $objWriter->writeAttribute('val', $subject->getBarDirection());
1025        $objWriter->endElement();
1026
1027        // c:grouping
1028        $objWriter->startElement('c:grouping');
1029        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1030        $objWriter->endElement();
1031
1032        // Write series
1033        $seriesIndex = 0;
1034        foreach ($subject->getSeries() as $series) {
1035            // c:ser
1036            $objWriter->startElement('c:ser');
1037
1038            // c:idx
1039            $objWriter->startElement('c:idx');
1040            $objWriter->writeAttribute('val', $seriesIndex);
1041            $objWriter->endElement();
1042
1043            // c:order
1044            $objWriter->startElement('c:order');
1045            $objWriter->writeAttribute('val', $seriesIndex);
1046            $objWriter->endElement();
1047
1048            // c:tx
1049            $objWriter->startElement('c:tx');
1050            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1051            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1052            $objWriter->endElement();
1053
1054            // Fills for points?
1055            $dataPointFills = $series->getDataPointFills();
1056            foreach ($dataPointFills as $key => $value) {
1057                // c:dPt
1058                $objWriter->startElement('c:dPt');
1059
1060                // c:idx
1061                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1062
1063                if (Fill::FILL_NONE != $value->getFillType()) {
1064                    // c:spPr
1065                    $objWriter->startElement('c:spPr');
1066                    // Write fill
1067                    $this->writeFill($objWriter, $value);
1068                    // ## c:spPr
1069                    $objWriter->endElement();
1070                }
1071
1072                // ## c:dPt
1073                $objWriter->endElement();
1074            }
1075
1076            // c:dLbls
1077            $objWriter->startElement('c:dLbls');
1078
1079            // c:txPr
1080            $objWriter->startElement('c:txPr');
1081
1082            // a:bodyPr
1083            $objWriter->writeElement('a:bodyPr', null);
1084
1085            // a:lstStyle
1086            $objWriter->writeElement('a:lstStyle', null);
1087
1088            // a:p
1089            $objWriter->startElement('a:p');
1090
1091            // a:pPr
1092            $objWriter->startElement('a:pPr');
1093
1094            // a:defRPr
1095            $objWriter->startElement('a:defRPr');
1096
1097            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1098            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1099            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1100            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1101            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1102            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1103            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1104
1105            // Font - a:solidFill
1106            $objWriter->startElement('a:solidFill');
1107
1108            $this->writeColor($objWriter, $series->getFont()->getColor());
1109
1110            $objWriter->endElement();
1111
1112            // Font - a:latin
1113            $objWriter->startElement('a:latin');
1114            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1115            $objWriter->endElement();
1116
1117            $objWriter->endElement();
1118
1119            $objWriter->endElement();
1120
1121            // a:endParaRPr
1122            $objWriter->startElement('a:endParaRPr');
1123            $objWriter->writeAttribute('lang', 'en-US');
1124            $objWriter->writeAttribute('dirty', '0');
1125            $objWriter->endElement();
1126
1127            $objWriter->endElement();
1128
1129            $objWriter->endElement();
1130
1131            // c:showVal
1132            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1133
1134            // c:showCatName
1135            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1136
1137            // c:showSerName
1138            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1139
1140            // c:showPercent
1141            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1142
1143            // c:showLeaderLines
1144            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1145
1146            $objWriter->endElement();
1147
1148            // c:spPr
1149            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1150                // c:spPr
1151                $objWriter->startElement('c:spPr');
1152                // Write fill
1153                $this->writeFill($objWriter, $series->getFill());
1154                // ## c:spPr
1155                $objWriter->endElement();
1156            }
1157
1158            // Write X axis data
1159            $axisXData = array_keys($series->getValues());
1160
1161            // c:cat
1162            $objWriter->startElement('c:cat');
1163            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1164            $objWriter->endElement();
1165
1166            // Write Y axis data
1167            $axisYData = array_values($series->getValues());
1168
1169            // c:val
1170            $objWriter->startElement('c:val');
1171            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1172            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1173            $objWriter->endElement();
1174
1175            $objWriter->endElement();
1176
1177            ++$seriesIndex;
1178        }
1179
1180        // c:gapWidth
1181        $objWriter->startElement('c:gapWidth');
1182        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1183        $objWriter->endElement();
1184
1185        // c:axId
1186        $objWriter->startElement('c:axId');
1187        $objWriter->writeAttribute('val', '52743552');
1188        $objWriter->endElement();
1189
1190        // c:axId
1191        $objWriter->startElement('c:axId');
1192        $objWriter->writeAttribute('val', '52749440');
1193        $objWriter->endElement();
1194
1195        // c:axId
1196        $objWriter->startElement('c:axId');
1197        $objWriter->writeAttribute('val', '0');
1198        $objWriter->endElement();
1199
1200        $objWriter->endElement();
1201    }
1202
1203    /**
1204     * Write Type Pie.
1205     *
1206     * @param XMLWriter $objWriter XML Writer
1207     *
1208     * @throws \Exception
1209     */
1210    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1211    {
1212        // c:pieChart
1213        $objWriter->startElement('c:doughnutChart');
1214
1215        // c:varyColors
1216        $objWriter->startElement('c:varyColors');
1217        $objWriter->writeAttribute('val', '1');
1218        $objWriter->endElement();
1219
1220        // Write series
1221        $seriesIndex = 0;
1222        foreach ($subject->getSeries() as $series) {
1223            // c:ser
1224            $objWriter->startElement('c:ser');
1225
1226            // c:idx
1227            $objWriter->startElement('c:idx');
1228            $objWriter->writeAttribute('val', $seriesIndex);
1229            $objWriter->endElement();
1230
1231            // c:order
1232            $objWriter->startElement('c:order');
1233            $objWriter->writeAttribute('val', $seriesIndex);
1234            $objWriter->endElement();
1235
1236            // c:tx
1237            $objWriter->startElement('c:tx');
1238            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1239            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1240            $objWriter->endElement();
1241
1242            // Fills for points?
1243            $dataPointFills = $series->getDataPointFills();
1244            foreach ($dataPointFills as $key => $value) {
1245                // c:dPt
1246                $objWriter->startElement('c:dPt');
1247                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1248                // c:dPt/c:spPr
1249                $objWriter->startElement('c:spPr');
1250                $this->writeFill($objWriter, $value);
1251                // c:dPt/##c:spPr
1252                $objWriter->endElement();
1253                // ##c:dPt
1254                $objWriter->endElement();
1255            }
1256
1257            // Write X axis data
1258            $axisXData = array_keys($series->getValues());
1259
1260            // c:cat
1261            $objWriter->startElement('c:cat');
1262            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1263            $objWriter->endElement();
1264
1265            // Write Y axis data
1266            $axisYData = array_values($series->getValues());
1267
1268            // c:val
1269            $objWriter->startElement('c:val');
1270            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1271            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1272            $objWriter->endElement();
1273
1274            $objWriter->endElement();
1275
1276            ++$seriesIndex;
1277        }
1278
1279        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1280            // c:dLbls
1281            $objWriter->startElement('c:dLbls');
1282
1283            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1284            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1285            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1286            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1287            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1288            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1289            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1290
1291            if ($series->hasDlblNumFormat()) {
1292                //c:numFmt
1293                $objWriter->startElement('c:numFmt');
1294                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1295                $objWriter->writeAttribute('sourceLinked', '0');
1296                $objWriter->endElement();
1297            }
1298
1299            // c:dLbls\c:txPr
1300            $objWriter->startElement('c:txPr');
1301            $objWriter->writeElement('a:bodyPr', null);
1302            $objWriter->writeElement('a:lstStyle', null);
1303
1304            // c:dLbls\c:txPr\a:p
1305            $objWriter->startElement('a:p');
1306
1307            // c:dLbls\c:txPr\a:p\a:pPr
1308            $objWriter->startElement('a:pPr');
1309
1310            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1311            $objWriter->startElement('a:defRPr');
1312            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1313            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1314            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1315            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1316            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1317            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1318            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1319
1320            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1321            $objWriter->startElement('a:solidFill');
1322            $this->writeColor($objWriter, $series->getFont()->getColor());
1323            $objWriter->endElement();
1324
1325            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1326            $objWriter->startElement('a:latin');
1327            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1328            $objWriter->endElement();
1329
1330            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1331            $objWriter->endElement();
1332            // c:dLbls\c:txPr\a:p\a:pPr\
1333            $objWriter->endElement();
1334
1335            // c:dLbls\c:txPr\a:p\a:endParaRPr
1336            $objWriter->startElement('a:endParaRPr');
1337            $objWriter->writeAttribute('lang', 'en-US');
1338            $objWriter->writeAttribute('dirty', '0');
1339            $objWriter->endElement();
1340
1341            // c:dLbls\c:txPr\a:p\
1342            $objWriter->endElement();
1343            // c:dLbls\c:txPr\
1344            $objWriter->endElement();
1345
1346            $separator = $series->getSeparator();
1347            if (!empty($separator) && PHP_EOL != $separator) {
1348                // c:dLbls\c:separator
1349                $objWriter->writeElement('c:separator', $separator);
1350            }
1351
1352            // c:dLbls\
1353            $objWriter->endElement();
1354        }
1355
1356        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1357        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1358
1359        $objWriter->endElement();
1360    }
1361
1362    /**
1363     * Write Type Pie.
1364     *
1365     * @param XMLWriter $objWriter XML Writer
1366     *
1367     * @throws \Exception
1368     */
1369    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1370    {
1371        // c:pieChart
1372        $objWriter->startElement('c:pieChart');
1373
1374        // c:varyColors
1375        $objWriter->startElement('c:varyColors');
1376        $objWriter->writeAttribute('val', '1');
1377        $objWriter->endElement();
1378
1379        // Write series
1380        $seriesIndex = 0;
1381        foreach ($subject->getSeries() as $series) {
1382            // c:ser
1383            $objWriter->startElement('c:ser');
1384
1385            // c:idx
1386            $objWriter->startElement('c:idx');
1387            $objWriter->writeAttribute('val', $seriesIndex);
1388            $objWriter->endElement();
1389
1390            // c:order
1391            $objWriter->startElement('c:order');
1392            $objWriter->writeAttribute('val', $seriesIndex);
1393            $objWriter->endElement();
1394
1395            // c:tx
1396            $objWriter->startElement('c:tx');
1397            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1398            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1399            $objWriter->endElement();
1400
1401            // Fills for points?
1402            $dataPointFills = $series->getDataPointFills();
1403            foreach ($dataPointFills as $key => $value) {
1404                // c:dPt
1405                $objWriter->startElement('c:dPt');
1406                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1407                // c:dPt/c:spPr
1408                $objWriter->startElement('c:spPr');
1409                $this->writeFill($objWriter, $value);
1410                // c:dPt/##c:spPr
1411                $objWriter->endElement();
1412                // ##c:dPt
1413                $objWriter->endElement();
1414            }
1415
1416            // c:dLbls
1417            $objWriter->startElement('c:dLbls');
1418
1419            if ($series->hasDlblNumFormat()) {
1420                //c:numFmt
1421                $objWriter->startElement('c:numFmt');
1422                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1423                $objWriter->writeAttribute('sourceLinked', '0');
1424                $objWriter->endElement();
1425            }
1426
1427            // c:txPr
1428            $objWriter->startElement('c:txPr');
1429
1430            // a:bodyPr
1431            $objWriter->writeElement('a:bodyPr', null);
1432
1433            // a:lstStyle
1434            $objWriter->writeElement('a:lstStyle', null);
1435
1436            // a:p
1437            $objWriter->startElement('a:p');
1438
1439            // a:pPr
1440            $objWriter->startElement('a:pPr');
1441
1442            // a:defRPr
1443            $objWriter->startElement('a:defRPr');
1444
1445            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1446            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1447            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1448            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1449            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1450            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1451            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1452
1453            // Font - a:solidFill
1454            $objWriter->startElement('a:solidFill');
1455
1456            $this->writeColor($objWriter, $series->getFont()->getColor());
1457
1458            $objWriter->endElement();
1459
1460            // Font - a:latin
1461            $objWriter->startElement('a:latin');
1462            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1463            $objWriter->endElement();
1464
1465            $objWriter->endElement();
1466
1467            $objWriter->endElement();
1468
1469            // a:endParaRPr
1470            $objWriter->startElement('a:endParaRPr');
1471            $objWriter->writeAttribute('lang', 'en-US');
1472            $objWriter->writeAttribute('dirty', '0');
1473            $objWriter->endElement();
1474
1475            $objWriter->endElement();
1476
1477            $objWriter->endElement();
1478
1479            // c:dLblPos
1480            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1481
1482            // c:showLegendKey
1483            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1484
1485            // c:showVal
1486            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1487
1488            // c:showCatName
1489            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1490
1491            // c:showSerName
1492            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1493
1494            // c:showPercent
1495            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1496
1497            // c:showLeaderLines
1498            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1499
1500            $objWriter->endElement();
1501
1502            // Write X axis data
1503            $axisXData = array_keys($series->getValues());
1504
1505            // c:cat
1506            $objWriter->startElement('c:cat');
1507            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1508            $objWriter->endElement();
1509
1510            // Write Y axis data
1511            $axisYData = array_values($series->getValues());
1512
1513            // c:val
1514            $objWriter->startElement('c:val');
1515            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1516            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1517            $objWriter->endElement();
1518
1519            $objWriter->endElement();
1520
1521            ++$seriesIndex;
1522        }
1523
1524        $objWriter->endElement();
1525    }
1526
1527    /**
1528     * Write Type Pie3D.
1529     *
1530     * @param XMLWriter $objWriter XML Writer
1531     *
1532     * @throws \Exception
1533     */
1534    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1535    {
1536        // c:pie3DChart
1537        $objWriter->startElement('c:pie3DChart');
1538
1539        // c:varyColors
1540        $objWriter->startElement('c:varyColors');
1541        $objWriter->writeAttribute('val', '1');
1542        $objWriter->endElement();
1543
1544        // Write series
1545        $seriesIndex = 0;
1546        foreach ($subject->getSeries() as $series) {
1547            // c:ser
1548            $objWriter->startElement('c:ser');
1549
1550            // c:idx
1551            $objWriter->startElement('c:idx');
1552            $objWriter->writeAttribute('val', $seriesIndex);
1553            $objWriter->endElement();
1554
1555            // c:order
1556            $objWriter->startElement('c:order');
1557            $objWriter->writeAttribute('val', $seriesIndex);
1558            $objWriter->endElement();
1559
1560            // c:tx
1561            $objWriter->startElement('c:tx');
1562            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1563            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1564            $objWriter->endElement();
1565
1566            // c:explosion
1567            $objWriter->startElement('c:explosion');
1568            $objWriter->writeAttribute('val', $subject->getExplosion());
1569            $objWriter->endElement();
1570
1571            // Fills for points?
1572            $dataPointFills = $series->getDataPointFills();
1573            foreach ($dataPointFills as $key => $value) {
1574                // c:dPt
1575                $objWriter->startElement('c:dPt');
1576                $this->writeElementWithValAttribute($objWriter, 'c:idx', $key);
1577                // c:dPt/c:spPr
1578                $objWriter->startElement('c:spPr');
1579                $this->writeFill($objWriter, $value);
1580                // c:dPt/##c:spPr
1581                $objWriter->endElement();
1582                // ##c:dPt
1583                $objWriter->endElement();
1584            }
1585
1586            // c:dLbls
1587            $objWriter->startElement('c:dLbls');
1588
1589            // c:txPr
1590            $objWriter->startElement('c:txPr');
1591
1592            // a:bodyPr
1593            $objWriter->writeElement('a:bodyPr', null);
1594
1595            // a:lstStyle
1596            $objWriter->writeElement('a:lstStyle', null);
1597
1598            // a:p
1599            $objWriter->startElement('a:p');
1600
1601            // a:pPr
1602            $objWriter->startElement('a:pPr');
1603
1604            // a:defRPr
1605            $objWriter->startElement('a:defRPr');
1606
1607            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1608            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1609            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1610            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1611            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1612            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1613            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1614
1615            // Font - a:solidFill
1616            $objWriter->startElement('a:solidFill');
1617
1618            $this->writeColor($objWriter, $series->getFont()->getColor());
1619
1620            $objWriter->endElement();
1621
1622            // Font - a:latin
1623            $objWriter->startElement('a:latin');
1624            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1625            $objWriter->endElement();
1626
1627            $objWriter->endElement();
1628
1629            $objWriter->endElement();
1630
1631            // a:endParaRPr
1632            $objWriter->startElement('a:endParaRPr');
1633            $objWriter->writeAttribute('lang', 'en-US');
1634            $objWriter->writeAttribute('dirty', '0');
1635            $objWriter->endElement();
1636
1637            $objWriter->endElement();
1638
1639            $objWriter->endElement();
1640
1641            // c:dLblPos
1642            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1643
1644            // c:showVal
1645            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1646
1647            // c:showCatName
1648            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1649
1650            // c:showSerName
1651            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1652
1653            // c:showPercent
1654            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1655
1656            // c:showLeaderLines
1657            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1658
1659            $objWriter->endElement();
1660
1661            // Write X axis data
1662            $axisXData = array_keys($series->getValues());
1663
1664            // c:cat
1665            $objWriter->startElement('c:cat');
1666            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1667            $objWriter->endElement();
1668
1669            // Write Y axis data
1670            $axisYData = array_values($series->getValues());
1671
1672            // c:val
1673            $objWriter->startElement('c:val');
1674            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1675            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1676            $objWriter->endElement();
1677
1678            $objWriter->endElement();
1679
1680            ++$seriesIndex;
1681        }
1682
1683        $objWriter->endElement();
1684    }
1685
1686    /**
1687     * Write Type Line.
1688     *
1689     * @param XMLWriter $objWriter XML Writer
1690     *
1691     * @throws \Exception
1692     */
1693    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1694    {
1695        // c:lineChart
1696        $objWriter->startElement('c:lineChart');
1697
1698        // c:grouping
1699        $objWriter->startElement('c:grouping');
1700        $objWriter->writeAttribute('val', 'standard');
1701        $objWriter->endElement();
1702
1703        // Write series
1704        $seriesIndex = 0;
1705        foreach ($subject->getSeries() as $series) {
1706            // c:ser
1707            $objWriter->startElement('c:ser');
1708
1709            // c:idx
1710            $objWriter->startElement('c:idx');
1711            $objWriter->writeAttribute('val', $seriesIndex);
1712            $objWriter->endElement();
1713
1714            // c:order
1715            $objWriter->startElement('c:order');
1716            $objWriter->writeAttribute('val', $seriesIndex);
1717            $objWriter->endElement();
1718
1719            // c:tx
1720            $objWriter->startElement('c:tx');
1721            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1722            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1723            $objWriter->endElement();
1724
1725            // c:spPr
1726            $objWriter->startElement('c:spPr');
1727            // Write fill
1728            $this->writeFill($objWriter, $series->getFill());
1729            // Write outline
1730            $this->writeOutline($objWriter, $series->getOutline());
1731            // ## c:spPr
1732            $objWriter->endElement();
1733
1734            // Marker
1735            $this->writeSeriesMarker($objWriter, $series->getMarker());
1736
1737            // c:dLbls
1738            $objWriter->startElement('c:dLbls');
1739
1740            // c:txPr
1741            $objWriter->startElement('c:txPr');
1742
1743            // a:bodyPr
1744            $objWriter->writeElement('a:bodyPr', null);
1745
1746            // a:lstStyle
1747            $objWriter->writeElement('a:lstStyle', null);
1748
1749            // a:p
1750            $objWriter->startElement('a:p');
1751
1752            // a:pPr
1753            $objWriter->startElement('a:pPr');
1754
1755            // a:defRPr
1756            $objWriter->startElement('a:defRPr');
1757
1758            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1759            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1760            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1761            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1762            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1763            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1764            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1765
1766            // Font - a:solidFill
1767            $objWriter->startElement('a:solidFill');
1768
1769            $this->writeColor($objWriter, $series->getFont()->getColor());
1770
1771            $objWriter->endElement();
1772
1773            // Font - a:latin
1774            $objWriter->startElement('a:latin');
1775            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1776            $objWriter->endElement();
1777
1778            $objWriter->endElement();
1779
1780            $objWriter->endElement();
1781
1782            // a:endParaRPr
1783            $objWriter->startElement('a:endParaRPr');
1784            $objWriter->writeAttribute('lang', 'en-US');
1785            $objWriter->writeAttribute('dirty', '0');
1786            $objWriter->endElement();
1787
1788            $objWriter->endElement();
1789
1790            $objWriter->endElement();
1791
1792            // c:showVal
1793            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1794
1795            // c:showCatName
1796            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1797
1798            // c:showSerName
1799            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1800
1801            // c:showPercent
1802            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1803
1804            // c:showLeaderLines
1805            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1806
1807            // > c:dLbls
1808            $objWriter->endElement();
1809
1810            // Write X axis data
1811            $axisXData = array_keys($series->getValues());
1812
1813            // c:cat
1814            $objWriter->startElement('c:cat');
1815            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1816            $objWriter->endElement();
1817
1818            // Write Y axis data
1819            $axisYData = array_values($series->getValues());
1820
1821            // c:val
1822            $objWriter->startElement('c:val');
1823            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1824            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1825            $objWriter->endElement();
1826
1827            // c:smooth
1828            $objWriter->startElement('c:smooth');
1829            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1830            $objWriter->endElement();
1831
1832            $objWriter->endElement();
1833
1834            ++$seriesIndex;
1835        }
1836
1837        // c:marker
1838        $objWriter->startElement('c:marker');
1839        $objWriter->writeAttribute('val', '1');
1840        $objWriter->endElement();
1841
1842        // c:axId
1843        $objWriter->startElement('c:axId');
1844        $objWriter->writeAttribute('val', '52743552');
1845        $objWriter->endElement();
1846
1847        // c:axId
1848        $objWriter->startElement('c:axId');
1849        $objWriter->writeAttribute('val', '52749440');
1850        $objWriter->endElement();
1851
1852        $objWriter->endElement();
1853    }
1854
1855    /**
1856     * Write Type Radar
1857     *
1858     * @param XMLWriter $objWriter XML Writer
1859     * @param Radar $subject
1860     * @param bool $includeSheet
1861     *
1862     * @throws \Exception
1863     */
1864    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1865    {
1866        // c:scatterChart
1867        $objWriter->startElement('c:radarChart');
1868
1869        // c:radarStyle
1870        $objWriter->startElement('c:radarStyle');
1871        $objWriter->writeAttribute('val', 'marker');
1872        $objWriter->endElement();
1873
1874        // c:varyColors
1875        $objWriter->startElement('c:varyColors');
1876        $objWriter->writeAttribute('val', '0');
1877        $objWriter->endElement();
1878
1879        // Write series
1880        $seriesIndex = 0;
1881        foreach ($subject->getSeries() as $series) {
1882            // c:ser
1883            $objWriter->startElement('c:ser');
1884
1885            // c:idx
1886            $objWriter->startElement('c:idx');
1887            $objWriter->writeAttribute('val', $seriesIndex);
1888            $objWriter->endElement();
1889
1890            // c:order
1891            $objWriter->startElement('c:order');
1892            $objWriter->writeAttribute('val', $seriesIndex);
1893            $objWriter->endElement();
1894
1895            // c:tx
1896            $objWriter->startElement('c:tx');
1897            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1898            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1899            $objWriter->endElement();
1900
1901            // Marker
1902            $this->writeSeriesMarker($objWriter, $series->getMarker());
1903
1904            // c:dLbls
1905            $objWriter->startElement('c:dLbls');
1906
1907            // c:txPr
1908            $objWriter->startElement('c:txPr');
1909
1910            // a:bodyPr
1911            $objWriter->writeElement('a:bodyPr', null);
1912
1913            // a:lstStyle
1914            $objWriter->writeElement('a:lstStyle', null);
1915
1916            // a:p
1917            $objWriter->startElement('a:p');
1918
1919            // a:pPr
1920            $objWriter->startElement('a:pPr');
1921
1922            // a:defRPr
1923            $objWriter->startElement('a:defRPr');
1924
1925            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1926            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1927            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1928            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1929            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1930            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1931            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1932
1933            // Font - a:solidFill
1934            $objWriter->startElement('a:solidFill');
1935
1936            $this->writeColor($objWriter, $series->getFont()->getColor());
1937
1938            $objWriter->endElement();
1939
1940            // Font - a:latin
1941            $objWriter->startElement('a:latin');
1942            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1943            $objWriter->endElement();
1944
1945            $objWriter->endElement();
1946
1947            $objWriter->endElement();
1948
1949            // a:endParaRPr
1950            $objWriter->startElement('a:endParaRPr');
1951            $objWriter->writeAttribute('lang', 'en-US');
1952            $objWriter->writeAttribute('dirty', '0');
1953            $objWriter->endElement();
1954
1955            $objWriter->endElement();
1956
1957            $objWriter->endElement();
1958
1959            // c:showLegendKey
1960            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1961
1962            // c:showVal
1963            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1964
1965            // c:showCatName
1966            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1967
1968            // c:showSerName
1969            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1970
1971            // c:showPercent
1972            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1973
1974            // c:showLeaderLines
1975            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1976
1977            $objWriter->endElement();
1978
1979            // c:spPr
1980            $objWriter->startElement('c:spPr');
1981            // Write fill
1982            $this->writeFill($objWriter, $series->getFill());
1983            // Write outline
1984            $this->writeOutline($objWriter, $series->getOutline());
1985            // ## c:spPr
1986            $objWriter->endElement();
1987
1988            // Write X axis data
1989            $axisXData = array_keys($series->getValues());
1990
1991            // c:cat
1992            $objWriter->startElement('c:cat');
1993            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1994            $objWriter->endElement();
1995
1996            // Write Y axis data
1997            $axisYData = array_values($series->getValues());
1998
1999            // c:val
2000            $objWriter->startElement('c:val');
2001            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2002            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2003            $objWriter->endElement();
2004
2005            // c:smooth
2006            $objWriter->startElement('c:smooth');
2007            $objWriter->writeAttribute('val', '0');
2008            $objWriter->endElement();
2009
2010            $objWriter->endElement();
2011
2012            ++$seriesIndex;
2013        }
2014
2015        // c:axId
2016        $objWriter->startElement('c:axId');
2017        $objWriter->writeAttribute('val', '52743552');
2018        $objWriter->endElement();
2019
2020        // c:axId
2021        $objWriter->startElement('c:axId');
2022        $objWriter->writeAttribute('val', '52749440');
2023        $objWriter->endElement();
2024
2025        $objWriter->endElement();
2026    }
2027
2028    /**
2029     * Write Type Scatter
2030     *
2031     * @throws \Exception
2032     */
2033    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2034    {
2035        // c:scatterChart
2036        $objWriter->startElement('c:scatterChart');
2037
2038        // c:scatterStyle
2039        $objWriter->startElement('c:scatterStyle');
2040        $objWriter->writeAttribute('val', 'lineMarker');
2041        $objWriter->endElement();
2042
2043        // c:varyColors
2044        $objWriter->startElement('c:varyColors');
2045        $objWriter->writeAttribute('val', '0');
2046        $objWriter->endElement();
2047
2048        // Write series
2049        $seriesIndex = 0;
2050        foreach ($subject->getSeries() as $series) {
2051            // c:ser
2052            $objWriter->startElement('c:ser');
2053
2054            // c:idx
2055            $objWriter->startElement('c:idx');
2056            $objWriter->writeAttribute('val', $seriesIndex);
2057            $objWriter->endElement();
2058
2059            // c:order
2060            $objWriter->startElement('c:order');
2061            $objWriter->writeAttribute('val', $seriesIndex);
2062            $objWriter->endElement();
2063
2064            // c:tx
2065            $objWriter->startElement('c:tx');
2066            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
2067            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2068            $objWriter->endElement();
2069
2070            // c:spPr
2071            $objWriter->startElement('c:spPr');
2072            // Write fill
2073            $this->writeFill($objWriter, $series->getFill());
2074            // Write outline
2075            $this->writeOutline($objWriter, $series->getOutline());
2076            // ## c:spPr
2077            $objWriter->endElement();
2078
2079            // Marker
2080            $this->writeSeriesMarker($objWriter, $series->getMarker());
2081
2082            // c:dLbls
2083            $objWriter->startElement('c:dLbls');
2084
2085            // c:txPr
2086            $objWriter->startElement('c:txPr');
2087
2088            // a:bodyPr
2089            $objWriter->writeElement('a:bodyPr', null);
2090
2091            // a:lstStyle
2092            $objWriter->writeElement('a:lstStyle', null);
2093
2094            // a:p
2095            $objWriter->startElement('a:p');
2096
2097            // a:pPr
2098            $objWriter->startElement('a:pPr');
2099
2100            // a:defRPr
2101            $objWriter->startElement('a:defRPr');
2102
2103            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2104            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2105            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2106            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2107            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2108            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2109            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2110
2111            // Font - a:solidFill
2112            $objWriter->startElement('a:solidFill');
2113
2114            $this->writeColor($objWriter, $series->getFont()->getColor());
2115
2116            $objWriter->endElement();
2117
2118            // Font - a:latin
2119            $objWriter->startElement('a:latin');
2120            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2121            $objWriter->endElement();
2122
2123            $objWriter->endElement();
2124
2125            $objWriter->endElement();
2126
2127            // a:endParaRPr
2128            $objWriter->startElement('a:endParaRPr');
2129            $objWriter->writeAttribute('lang', 'en-US');
2130            $objWriter->writeAttribute('dirty', '0');
2131            $objWriter->endElement();
2132
2133            $objWriter->endElement();
2134
2135            $objWriter->endElement();
2136
2137            // c:showLegendKey
2138            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2139
2140            // c:showVal
2141            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2142
2143            // c:showCatName
2144            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2145
2146            // c:showSerName
2147            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2148
2149            // c:showPercent
2150            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2151
2152            // c:separator
2153            $separator = $series->getSeparator();
2154            if (!empty($separator) && PHP_EOL != $separator) {
2155                // c:dLbls\c:separator
2156                $objWriter->writeElement('c:separator', $separator);
2157            }
2158
2159            // c:showLeaderLines
2160            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2161
2162            $objWriter->endElement();
2163
2164            // Write X axis data
2165            $axisXData = array_keys($series->getValues());
2166
2167            // c:xVal
2168            $objWriter->startElement('c:xVal');
2169            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2170            $objWriter->endElement();
2171
2172            // Write Y axis data
2173            $axisYData = array_values($series->getValues());
2174
2175            // c:yVal
2176            $objWriter->startElement('c:yVal');
2177            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2178            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2179            $objWriter->endElement();
2180
2181            // c:smooth
2182            $objWriter->startElement('c:smooth');
2183            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2184            $objWriter->endElement();
2185
2186            $objWriter->endElement();
2187
2188            ++$seriesIndex;
2189        }
2190
2191        // c:axId
2192        $objWriter->startElement('c:axId');
2193        $objWriter->writeAttribute('val', '52743552');
2194        $objWriter->endElement();
2195
2196        // c:axId
2197        $objWriter->startElement('c:axId');
2198        $objWriter->writeAttribute('val', '52749440');
2199        $objWriter->endElement();
2200
2201        $objWriter->endElement();
2202    }
2203
2204    /**
2205     * Write chart relationships to XML format.
2206     *
2207     * @return string XML Output
2208     *
2209     * @throws \Exception
2210     */
2211    public function writeChartRelationships(Chart $pChart): string
2212    {
2213        // Create XML writer
2214        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2215
2216        // XML header
2217        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2218
2219        // Relationships
2220        $objWriter->startElement('Relationships');
2221        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2222
2223        // Write spreadsheet relationship?
2224        if ($pChart->hasIncludedSpreadsheet()) {
2225            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2226        }
2227
2228        $objWriter->endElement();
2229
2230        // Return
2231        return $objWriter->getData();
2232    }
2233
2234    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2235    {
2236        // c:marker
2237        $objWriter->startElement('c:marker');
2238        // c:marker > c:symbol
2239        $objWriter->startElement('c:symbol');
2240        $objWriter->writeAttribute('val', $marker->getSymbol());
2241        $objWriter->endElement();
2242
2243        // Size if different of none
2244        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2245            $markerSize = (int) $marker->getSize();
2246            if ($markerSize < 2) {
2247                $markerSize = 2;
2248            }
2249            if ($markerSize > 72) {
2250                $markerSize = 72;
2251            }
2252
2253            /*
2254             * c:marker > c:size
2255             * Size in points
2256             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2257             */
2258            $objWriter->startElement('c:size');
2259            $objWriter->writeAttribute('val', $markerSize);
2260            $objWriter->endElement();
2261        }
2262
2263        // // c:marker > c:spPr
2264        $objWriter->startElement('c:spPr');
2265        $this->writeFill($objWriter, $marker->getFill());
2266        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2267        $objWriter->endElement();
2268
2269        // > c:marker
2270        $objWriter->endElement();
2271    }
2272
2273    /**
2274     * @throws \Exception
2275     */
2276    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2277    {
2278        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2279            return;
2280        }
2281
2282        if (Chart\Axis::AXIS_X == $typeAxis) {
2283            $mainElement = 'c:catAx';
2284            $axIdVal = '52743552';
2285            $axPosVal = 'b';
2286            $crossAxVal = '52749440';
2287        } else {
2288            $mainElement = 'c:valAx';
2289            $axIdVal = '52749440';
2290            $axPosVal = 'l';
2291            $crossAxVal = '52743552';
2292        }
2293
2294        // $mainElement
2295        $objWriter->startElement($mainElement);
2296
2297        // $mainElement > c:axId
2298        $objWriter->startElement('c:axId');
2299        $objWriter->writeAttribute('val', $axIdVal);
2300        $objWriter->endElement();
2301
2302        // $mainElement > c:scaling
2303        $objWriter->startElement('c:scaling');
2304
2305        // $mainElement > c:scaling > c:orientation
2306        $objWriter->startElement('c:orientation');
2307        $objWriter->writeAttribute('val', 'minMax');
2308        $objWriter->endElement();
2309
2310        if (null != $oAxis->getMaxBounds()) {
2311            $objWriter->startElement('c:max');
2312            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2313            $objWriter->endElement();
2314        }
2315
2316        if (null != $oAxis->getMinBounds()) {
2317            $objWriter->startElement('c:min');
2318            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2319            $objWriter->endElement();
2320        }
2321
2322        // $mainElement > ##c:scaling
2323        $objWriter->endElement();
2324
2325        // $mainElement > c:delete
2326        $objWriter->startElement('c:delete');
2327        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2328        $objWriter->endElement();
2329
2330        // $mainElement > c:axPos
2331        $objWriter->startElement('c:axPos');
2332        $objWriter->writeAttribute('val', $axPosVal);
2333        $objWriter->endElement();
2334
2335        $oMajorGridlines = $oAxis->getMajorGridlines();
2336        if ($oMajorGridlines instanceof Gridlines) {
2337            $objWriter->startElement('c:majorGridlines');
2338
2339            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2340
2341            $objWriter->endElement();
2342        }
2343
2344        $oMinorGridlines = $oAxis->getMinorGridlines();
2345        if ($oMinorGridlines instanceof Gridlines) {
2346            $objWriter->startElement('c:minorGridlines');
2347
2348            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2349
2350            $objWriter->endElement();
2351        }
2352
2353        if ('' != $oAxis->getTitle()) {
2354            // c:title
2355            $objWriter->startElement('c:title');
2356
2357            // c:tx
2358            $objWriter->startElement('c:tx');
2359
2360            // c:rich
2361            $objWriter->startElement('c:rich');
2362
2363            // a:bodyPr
2364            $objWriter->startElement('a:bodyPr');
2365            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle($oAxis->getTitleRotation()));
2366            $objWriter->endElement();
2367
2368            // a:lstStyle
2369            $objWriter->writeElement('a:lstStyle', null);
2370
2371            // a:p
2372            $objWriter->startElement('a:p');
2373
2374            // a:pPr
2375            $objWriter->startElement('a:pPr');
2376
2377            // a:defRPr
2378            $objWriter->startElement('a:defRPr');
2379
2380            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2381            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2382            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2383            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2384            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2385            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2386            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2387
2388            // Font - a:solidFill
2389            $objWriter->startElement('a:solidFill');
2390            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2391            $objWriter->endElement();
2392
2393            // Font - a:latin
2394            $objWriter->startElement('a:latin');
2395            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2396            $objWriter->endElement();
2397
2398            $objWriter->endElement();
2399
2400            // ## a:pPr
2401            $objWriter->endElement();
2402
2403            // a:r
2404            $objWriter->startElement('a:r');
2405
2406            // a:rPr
2407            $objWriter->startElement('a:rPr');
2408            $objWriter->writeAttribute('lang', 'en-US');
2409            $objWriter->writeAttribute('dirty', '0');
2410            $objWriter->endElement();
2411
2412            // a:t
2413            $objWriter->writeElement('a:t', $oAxis->getTitle());
2414
2415            // ## a:r
2416            $objWriter->endElement();
2417
2418            // a:endParaRPr
2419            $objWriter->startElement('a:endParaRPr');
2420            $objWriter->writeAttribute('lang', 'en-US');
2421            $objWriter->writeAttribute('dirty', '0');
2422            $objWriter->endElement();
2423
2424            // ## a:p
2425            $objWriter->endElement();
2426
2427            // ## c:rich
2428            $objWriter->endElement();
2429
2430            // ## c:tx
2431            $objWriter->endElement();
2432
2433            // ## c:title
2434            $objWriter->endElement();
2435        }
2436
2437        // c:numFmt
2438        $objWriter->startElement('c:numFmt');
2439        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2440        $objWriter->writeAttribute('sourceLinked', '1');
2441        $objWriter->endElement();
2442
2443        // c:majorTickMark
2444        $objWriter->startElement('c:majorTickMark');
2445        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2446        $objWriter->endElement();
2447
2448        // c:minorTickMark
2449        $objWriter->startElement('c:minorTickMark');
2450        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2451        $objWriter->endElement();
2452
2453        // c:tickLblPos
2454        $objWriter->startElement('c:tickLblPos');
2455        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2456        $objWriter->endElement();
2457
2458        // c:spPr
2459        $objWriter->startElement('c:spPr');
2460        // Outline
2461        $this->writeOutline($objWriter, $oAxis->getOutline());
2462        // ##c:spPr
2463        $objWriter->endElement();
2464
2465        // c:crossAx
2466        $objWriter->startElement('c:crossAx');
2467        $objWriter->writeAttribute('val', $crossAxVal);
2468        $objWriter->endElement();
2469
2470        // c:crosses
2471        $objWriter->startElement('c:crosses');
2472        $objWriter->writeAttribute('val', 'autoZero');
2473        $objWriter->endElement();
2474
2475        if (Chart\Axis::AXIS_X == $typeAxis) {
2476            // c:lblAlgn
2477            $objWriter->startElement('c:lblAlgn');
2478            $objWriter->writeAttribute('val', 'ctr');
2479            $objWriter->endElement();
2480
2481            // c:lblOffset
2482            $objWriter->startElement('c:lblOffset');
2483            $objWriter->writeAttribute('val', '100');
2484            $objWriter->endElement();
2485
2486            // c:majorUnit
2487            if ($oAxis->getMajorUnit() != null) {
2488                $objWriter->startElement('c:tickLblSkip');
2489                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2490                $objWriter->endElement();
2491            }
2492        }
2493
2494        if (Chart\Axis::AXIS_Y == $typeAxis) {
2495            // c:crossBetween
2496            $objWriter->startElement('c:crossBetween');
2497            // midCat : Position Axis On Tick Marks
2498            // between : Between Tick Marks
2499            if ($typeChart instanceof Area) {
2500                $objWriter->writeAttribute('val', 'midCat');
2501            } else {
2502                $objWriter->writeAttribute('val', 'between');
2503            }
2504            $objWriter->endElement();
2505
2506            // c:majorUnit
2507            if (null != $oAxis->getMajorUnit()) {
2508                $objWriter->startElement('c:majorUnit');
2509                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2510                $objWriter->endElement();
2511            }
2512
2513            // c:minorUnit
2514            if (null != $oAxis->getMinorUnit()) {
2515                $objWriter->startElement('c:minorUnit');
2516                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2517                $objWriter->endElement();
2518            }
2519        }
2520
2521        $objWriter->endElement();
2522    }
2523
2524    /**
2525     * @throws \Exception
2526     */
2527    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2528    {
2529        // c:spPr
2530        $objWriter->startElement('c:spPr');
2531
2532        // Outline
2533        $this->writeOutline($objWriter, $oGridlines->getOutline());
2534
2535        // ##c:spPr
2536        $objWriter->endElement();
2537    }
2538}